package com.suxii.widget;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;

import androidx.core.view.GestureDetectorCompat;


public class SlideMenuView extends ViewGroup {

    /**
     * 当布局宽度为 wrap_content 的时候.默认的宽度
     */
    private static final int DEFAULT_WIDTH = 0;
    /**
     * 当布局高度为 wrap_content 的时候.默认的高度
     */
    private static final int DEFAULT_HEIGHT = 0;


    /**
     * 手势检测器
     */
    private final GestureDetectorCompat gestureDetectorCompat;
    /**
     * 侧滑菜单最大可以滑动的长度
     */
    private int maxSlideLength;

    /**
     * 滑动菜单布局
     */
    private View slide;
    /**
     * 主界面内容布局
     */
    private View container;
    /**
     * 侧滑菜单开启状态
     */
    private boolean isOpen = false;

    /**
     * 主内容布局的 left 值.主要通过手势滑动来改变该值,来实现内容布局位置的改变
     */
    private int containerLeft = 0;
    /**
     * 主内容布局的 top 值.暂时没用到
     */
    private int containerTop = 0;


    /**
     * 构造器,目前只支持在布局标签中使用该Layout. 如需在 Java 中创建,请创建1个参数的构造器
     *
     * @param context
     * @param attrs
     */
    public SlideMenuView(Context context, AttributeSet attrs) {
        super(context, attrs);
        gestureDetectorCompat = new GestureDetectorCompat(context, listener);
        gestureDetectorCompat.setIsLongpressEnabled(false);
    }


    /**
     * 设置 子 View 的布局参数,方便获取 Margin 值
     *
     * @param attrs
     *
     * @return
     */
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }


    public boolean isOpen() {
        return isOpen;
    }


    /**
     * 手动设置菜单开启
     */
    public void open() {
        if (isOpen)
            return;
        isOpen = true;
        containerLeft = maxSlideLength;
        requestLayout();
    }

    /**
     * 手动设置菜单关闭
     */
    public void close() {
        if (!isOpen)
            return;
        isOpen = false;
        containerLeft = 0;
        requestLayout();
    }

    /**
     * 布局测量
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (getChildCount() != 2)
            throw new IllegalArgumentException("SlideMenuView 有且只能有 2 个子View");
        //测量侧滑布局
        slide = getChildAt(0);
        measureChild(slide, widthMeasureSpec, heightMeasureSpec);
        maxSlideLength = slide.getMeasuredWidth();
        //测量主内容布局
        container = getChildAt(1);
        measureChild(container, widthMeasureSpec, heightMeasureSpec);
        int resultWidth = getSize(DEFAULT_WIDTH, widthMeasureSpec);
        int resultHeight = getSize(DEFAULT_HEIGHT, heightMeasureSpec);
        setMeasuredDimension(resultWidth, resultHeight);
    }

    /**
     * 布局本身的宽高测量封装方法
     *
     * @param defaultSize 当 宽或高为 wrap_content 时,默认尺寸
     * @param measureSpec
     *
     * @return
     */
    private int getSize(int defaultSize, int measureSpec) {
        int result = defaultSize;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        switch (specMode) {
            case MeasureSpec.AT_MOST:
                result = defaultSize;
                break;
            case MeasureSpec.EXACTLY:
            case MeasureSpec.UNSPECIFIED:
                result = specSize;
                break;
        }
        return result;
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        int left = containerLeft, top = containerTop, right, bottom;
        right = left + container.getMeasuredWidth();
        bottom = top + container.getMeasuredHeight();

        //确定主内容布局位置
        container.layout(left, top, right, bottom);


        right = left / 2 + maxSlideLength / 2;
        left = right - slide.getMeasuredWidth();
        //确定侧滑布局位置
        slide.layout(left, top, right, bottom);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //事件交由 手势检测器 处理
        gestureDetectorCompat.onTouchEvent(event);

        //由于手势检测器 在滑动事件过后没有 ACTION_UP 相关的事件,所以需要自己处理
        if (isScroll) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                    if (containerLeft != 0 && containerLeft != maxSlideLength) {
                        int end = containerLeft > maxSlideLength * 2 / 3 ? maxSlideLength : 0;
                        resetSlide(end);
                    }
                    break;
            }
        }
        return true;
    }

    /**
     * 开启动画,关闭/打开菜单
     *
     * @param end
     */
    private void resetSlide(int end) {
        long duration = 300 * Math.abs(end - containerLeft) / maxSlideLength;
        ValueAnimator valueAnimator = ValueAnimator.ofInt(containerLeft, end).setDuration(duration);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                containerLeft = (int) animation.getAnimatedValue();
                requestLayout();
                callbackSlide();
            }
        });
        //监听动画完成事件
        valueAnimator.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationEnd(Animator animation) {
                isOpen = containerLeft != 0;
                if (callback != null) {
                    if (isOpen) {
                        callback.onOpen();
                    } else {
                        callback.onClose();
                    }
                }
            }
        });
        valueAnimator.start();
    }

    /**
     * 判断是否经过滑动,防止用户点击也触发相应的回调
     */
    private boolean isScroll;

    /**
     * 手势检测监听器
     */
    private GestureDetector.SimpleOnGestureListener listener = new GestureDetector.SimpleOnGestureListener() {

        @Override
        public boolean onDown(MotionEvent e) {
            isScroll = false;
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (velocityX > 1000 && containerLeft != maxSlideLength) {
                //打开
                isScroll = false;
                resetSlide(maxSlideLength);
            } else if (velocityX < -1000 && containerLeft != 0) {
                //关闭
                isScroll = false;
                resetSlide(0);
            }
//            Log.d("ABC", "onScroll: " + velocityX);
            return super.onFling(e1, e2, velocityX, velocityY);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            isScroll = true;
//            Log.d("ABC", "onScroll: " + distanceX);
            containerLeft -= distanceX;
            containerLeft = containerLeft <= 0 ? 0 : containerLeft >= maxSlideLength ? maxSlideLength : containerLeft;
            //重新 onLayout
            requestLayout();
            callbackSlide();
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    };

    /**
     * 回调滑动过程
     */
    private void callbackSlide() {
        if (callback != null) {
            if ((isOpen && containerLeft == maxSlideLength) || (!isOpen && containerLeft == 0))
                return;
            float f = 1.0f * containerLeft / maxSlideLength;
            callback.onSlide(f, containerLeft);
        }
    }


    /**
     * 滑动回调
     */
    public interface OnSlideCallback {

        /**
         * 侧滑菜单完全打开
         */
        void onOpen();

        /**
         * 侧滑菜单完全关闭
         */
        void onClose();


        /**
         * 侧滑菜单滑动
         *
         * @param slide 距离百分比
         * @param pixel 距离像素值
         */
        void onSlide(float slide, int pixel);
    }

    private OnSlideCallback callback;

    /**
     * 设置滑动监听回调函数
     *
     * @param callback
     */
    public void setOnSlideCallback(OnSlideCallback callback) {
        this.callback = callback;
    }


    private float downX,downY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();

                break;
            case MotionEvent.ACTION_MOVE:
                if (downX>getWidth()/2){
                    return false;
                }
                //根据偏移量判断是否拦截
                float offsetX = event.getX() - downX;
                float offsetY = Math.abs(event.getY() - downY);
                //当左右滑动偏移量大于上下滑动偏移量，且偏移量大于5时（）,进行拦截处理
                if (Math.abs(offsetX) > offsetY && offsetX > 5) {
                    return true;//拦截触摸事件，不往里传递，交个自己的OnTouchEvent处理
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.onInterceptTouchEvent(event);//默认返回false不拦截
    }


}
